package com.hznc.wcs.controller.flowable;

import com.diboot.core.vo.JsonResult;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author GaoGuoPei
 * @describe
 * @date 2024/3/21
 **/
@RestController
@RequestMapping("/flowable/process")
public class ProcessController {
    @Resource
    private TaskService taskService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private HistoryService historyService;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ProcessEngine processEngine;

//    public ProcessController(TaskService taskService, RuntimeService runtimeService, HistoryService historyService, RepositoryService repositoryService, ProcessEngine processEngine) {
//        this.taskService = taskService;
//        this.runtimeService = runtimeService;
//        this.historyService = historyService;
//        this.repositoryService = repositoryService;
//        this.processEngine = processEngine;
//    }

    /**
     * 开启流程实例
     * @param variables
     * @return
     * @throws Exception
     */
    @PostMapping("/run")
    public JsonResult run(@RequestBody Map<String, Object> variables) throws Exception {
        String processDefinitionId = variables.get("processDefinitionId").toString();
        variables.remove("processDefinitionId");
        //设置流程发起人
//        Authentication.setAuthenticatedUserId(variables.get("userId").toString());

        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variables);

        //这个方法最终使用一个ThreadLocal类型的变量进行存储，也就是与当前的线程绑定，所以流程实例启动完毕之后，需要设置为null，防止多线程的时候出问题。
//        Authentication.setAuthenticatedUserId(null);

        //发起申请后的第一步 可以像下面一样选择直接完成这个任务，相当于自己审批过去自己的申请
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        // taskService.complete 完成这个任务  有三种参数方式，比如可以给下一个流程带过去参数
        taskService.complete(task.getId());

        HashMap<String, String> map = new HashMap<>();
        map.put("TaskId", task.getId());
        return JsonResult.OK(map);
    }

    /**
     * 通过tsakId 获取流程的当前状态
     * @param taskId
     * @return
     * @throws Exception
     */
    @GetMapping("/genProcessDiagrams")
    public JsonResult genProcessDiagrams(@RequestParam String taskId, HttpServletResponse httpServletResponse) throws Exception {
        String processId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        HistoricProcessInstance his = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
        String pdi="";
        //流程走完的不显示图
        if (pi == null) {
            pdi=his.getProcessDefinitionId();
        }else {
            pdi=pi.getProcessDefinitionId();
        }
        if(pdi==""){
            return null;
        }
        //获得活动的节点
        List<HistoricActivityInstance> historyProcess =  historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pdi);
        for (HistoricActivityInstance hi : historyProcess) {
            String activityType = hi.getActivityType();
            if (activityType.equals("sequenceFlow") || activityType.equals("exclusiveGateway")) {
                flows.add(hi.getActivityId());
            } else if (activityType.equals("userTask") || activityType.equals("startEvent")) {
                activityIds.add(hi.getActivityId());
            }
        }
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processId).list();
        for (Task task : tasks) {
            activityIds.add(task.getTaskDefinitionKey());
        }
        ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
        engConf.setActivityFontName("宋体");
        engConf.setLabelFontName("宋体");
        engConf.setAnnotationFontName("宋体");
        //定义流程画布生成器
        ProcessDiagramGenerator processDiagramGenerator = engConf.getProcessDiagramGenerator();
        InputStream in = processDiagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engConf.getActivityFontName()
                , engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);

        // 设置响应的类型格式为图片格式
        httpServletResponse.setContentType("image/png");
        //禁止图像缓存。
        httpServletResponse.setHeader("Pragma", "no-cache");
        httpServletResponse.setHeader("Cache-Control", "no-cache");
        httpServletResponse.setDateHeader("Expires", 0);

        String base64Img = null;
        try {
            // in.available()返回文件的字节长度
            byte[] buf = new byte[in.available()];
            // 将文件中的内容读入到数组中
            in.read(buf);
            // 进行Base64编码处理
            base64Img = new String(Base64Utils.encode(buf), StandardCharsets.UTF_8);
        }catch (IOException e){
            e.printStackTrace();
        } finally {
            if (in != null) {
                in.close();
            }
        }
        return JsonResult.OK(base64Img);
    }

    /**
     * 获取所有流程实例
     * @param variables
     * @return
     * @throws Exception
     */
    @PostMapping("/getAllProcessInstance")
    public JsonResult getAllProcessInstance(@RequestBody Map<String, Object> variables) throws Exception {
        if(variables.get("processInstanceId")==null){
            List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().list();
            return JsonResult.OK(list);
        }else {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(variables.get("processInstanceId").toString()).singleResult();
            return JsonResult.OK(historicProcessInstance);

        }
    }
}
